using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Web.UI;

namespace WebForms.ControlExtender
{
    public class TargetControlPropertiesCollection<T> : List<T>, IStateManager where T : TargetControlProperties, new()
    {
        private bool _isTrackingViewState;
        private bool _saveAll;

        #region Workaround 'ambigious match found'

        // http://support.microsoft.com/default.aspx?scid=kb;EN-US;823194        
        public T this[object obj]
        {
            get { return base[IndexOf(obj)]; }
            set { base[IndexOf(obj)] = value; }
        }

        public int IndexOf(object obj)
        {
            if (obj is int)
                return (int) obj;

            if (obj is string)
            {
                for (int i = 0; i < Count; i++)
                    if ((base[i]).ControlId == obj.ToString())
                        return i;
                return -1;
            }
            throw new ArgumentException("Only a string or an integer is permitted for the indexer.");
        }

        #endregion

        #region IStateManager Members

        public bool IsTrackingViewState
        {
            get { return _isTrackingViewState; }
        }

        public void LoadViewState(object savedState)
        {
            Trace.WriteLine("LoadViewState");
            if (savedState == null)
            {
                return;
            }

            if (savedState is ArrayList)
            {
                // All items were saved.
                // Create new DefaultButtonSettings collection using view state.
                _saveAll = true;
                ArrayList states = (ArrayList) savedState;

                Clear();
                foreach (object t in states)
                {
                    T item = new T();
                    Add(item);
                    ((IStateManager) item).LoadViewState(t);
                }
            }
            else
            {
                // Load modified items.
                Pair p = (Pair) savedState;
                ArrayList indices = (ArrayList) p.First;
                ArrayList states = (ArrayList) p.Second;

                for (int i = 0; i < indices.Count; i++)
                {
                    int index = (int) indices[i];
                    if (index < Count)
                        ((IStateManager) this[index]).LoadViewState(states[i]);
                    else
                    {
                        T item = new T();
                        Add(item);
                        ((IStateManager) item).LoadViewState(states[i]);
                    }
                }
            }
        }

        public object SaveViewState()
        {
            if (_saveAll)
            {
                // Save all items.
                ArrayList states = new ArrayList(Count);
                for (int i = 0; i < Count; i++)
                {
                    T item = this[i];
                    item.SetDirty();
                    states.Add(((IStateManager) item).SaveViewState());
                }
                return states.Count > 0 ? states : null;
            }
            else
            {
                // Save only the dirty items.
                ArrayList indices = new ArrayList();
                ArrayList states = new ArrayList();

                for (int i = 0; i < Count; i++)
                {
                    T item = this[i];
                    object state = ((IStateManager) item).SaveViewState();
                    if (state != null)
                    {
                        states.Add(state);
                        indices.Add(i);
                    }
                }

                return indices.Count > 0 ? new Pair(indices, states) : null;
            }
        }

        public void TrackViewState()
        {
            _isTrackingViewState = true;
            foreach (T item in this)
                ((IStateManager) item).TrackViewState();
        }

        #endregion

        public bool Contains(object obj)
        {
            for (int i = 0; i < Count; i++)
                if ((this[i]).ControlId == obj.ToString())
                    return true;
            return false;
        }

        public new void Add(T item)
        {
            base.Add(item);
            if (_isTrackingViewState)
            {
                ((IStateManager) item).TrackViewState();
                item.SetDirty();
            }
        }

        public new void Clear()
        {
            base.Clear();
            if (_isTrackingViewState)
                _saveAll = true;
        }

        public new void Insert(int index, T item)
        {
            base.Insert(index, item);

            if (_isTrackingViewState)
            {
                ((IStateManager) item).TrackViewState();
                _saveAll = true;
            }
        }

        public new void RemoveAt(int index)
        {
            base.RemoveAt(index);
            if (_isTrackingViewState)
                _saveAll = true;
        }

        public new void Remove(T item)
        {
            base.Remove(item);
            if (_isTrackingViewState)
                _saveAll = true;
        }
    }
}